signature X86ASM_STRUCTS =
sig
  include ATOMS
  structure Types : TYPES2
end

signature X86ASM =
sig
  include X86ASM_STRUCTS

  structure Cmd :
  sig
    datatype t
      = Add
      | Sub
      | Mul
      | Div
      | And
      | Or
      | Xor
      | Not
      | Mov
      | Cmp
      | Push
      | Pop
      | Jne
      | Jmp
      | Call
      | Ret
      | Setg
      | Setl
      | Setle
      | Sete
      | Setne
      | Setge
      | Prolog
      | Epilog
    
    val toString : t -> string
  end
  
  structure Register :
  sig
    datatype t
      = eax | ebx | ecx | edx | esi | edi | ebp | esp
      
    val toString : t -> string
  end
  
  structure Location :
  sig
    datatype t
      = InStack of Intl.t
      | InReg of Register.t
      | Global
    
    val toString : t -> string
  end
  
  structure Operand :
  sig
    datatype t
      = OpVoid
      | IntNum of Intl.t
      | True
      | False
      | Null
      | Reg of {reg: Register.t, ty : Types.t}
      | Rmem of {off: Intl.t, reg: Register.t, ty : Types.t}
      | Label of {id : Id.t, ty : Types.t}
    
    val toString : t -> string
  end
  
  structure Ins :
  sig
    datatype t
      = I of {cmd : Cmd.t, src : Operand.t, dest : Operand.t}
      
    val toString : t -> string
  end
  
  structure Block :
  sig
    datatype t
      = T of {name : Id.t,
              prop : bool,
              ins : Ins.t list,
              successors : Id.t list} 
              (* the first successor is the direct successor,
               * Example:  je l (l1) ====>
               * the successors are [l1, l]
               *)
    val name : t -> Id.t
    val addInsHead : t * Ins.t list -> t
    val addInsTail : t * Ins.t list -> t
    val getIns : t -> Ins.t list
    val toString : t -> string
    
  end
  
  structure Function :
  sig
    datatype t
      = T of {name : Id.t,
              exit : Id.t,
              rettype : Types.t,
              args : {id : Id.t, ty : Types.t} list,
              locals : {id : Id.t, ty : Types.t} list,
              blocks : Block.t list,
              pre : Operand.t,
              post : Operand.t}
              
    val toString : t -> string
  end
  
  structure Structs :
  sig
    datatype t
      = T of {name : Id.t,
              fields : {id : Id.t, ty : Types.t} list}
              
    val toString : t -> string
  end
  
  structure Program :
  sig
    datatype t
      = T of {structs : Structs.t list,
              gvars : {id : Id.t, ty : Types.t} list,
              funcs : Function.t list}
    val toString : t -> string
  end
end
